import warnings
warnings.filterwarnings(action = 'ignore')
import math
import geopandas as gpd
import pandas as pd
from shapely.geometry import MultiPolygon
import folium
from folium import Choropleth, Marker
from folium.plugins import HeatMap, MarkerClusterKaggle Geospatial Analysis Exercise 5
이 노트북은 Kaggle Geospatial Analysis의 Exercise 입니다. 이 링크로 튜토리얼을 볼 수 있습니다.
소개
위기 대응팀의 일원으로 뉴욕 시에서 발생한 충돌 사고에 대해 병원들이 어떻게 대응하고 있는지 파악해봅시다.
embed_map() 함수를 사용해 지도를 시각화해봅시다.
def embed_map(m, file_name) :
from IPython.display import IFrame
m.save(file_name)
return IFrame(file_name, width = '100%', height = '500px')1) 충돌 데이터 시각화
다음 셀을 실행하여 2013~2018년 주요 자동차 충돌을 추적하는 collisions GeoDataFrame을 로드해보세요.
collisions = gpd.read_file('./geospatial-learn-course-data/NYPD_Motor_Vehicle_Collisions/NYPD_Motor_Vehicle_Collisions/NYPD_Motor_Vehicle_Collisions.shp')
collisions.head()| DATE | TIME | BOROUGH | ZIP CODE | LATITUDE | LONGITUDE | LOCATION | ON STREET | CROSS STRE | OFF STREET | ... | CONTRIBU_2 | CONTRIBU_3 | CONTRIBU_4 | UNIQUE KEY | VEHICLE TY | VEHICLE _1 | VEHICLE _2 | VEHICLE _3 | VEHICLE _4 | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 07/30/2019 | 0:00 | BRONX | 10464 | 40.841100 | -73.784960 | (40.8411, -73.78496) | None | None | 121 PILOT STREET | ... | Unspecified | None | None | 4180045 | Sedan | Station Wagon/Sport Utility Vehicle | Station Wagon/Sport Utility Vehicle | None | None | POINT (1043750.211 245785.815) |
| 1 | 07/30/2019 | 0:10 | QUEENS | 11423 | 40.710827 | -73.770660 | (40.710827, -73.77066) | JAMAICA AVENUE | 188 STREET | None | ... | None | None | None | 4180007 | Sedan | Sedan | None | None | None | POINT (1047831.185 198333.171) |
| 2 | 07/30/2019 | 0:25 | None | None | 40.880318 | -73.841286 | (40.880318, -73.841286) | BOSTON ROAD | None | None | ... | None | None | None | 4179575 | Sedan | Station Wagon/Sport Utility Vehicle | None | None | None | POINT (1028139.293 260041.178) |
| 3 | 07/30/2019 | 0:35 | MANHATTAN | 10036 | 40.756744 | -73.984590 | (40.756744, -73.98459) | None | None | 155 WEST 44 STREET | ... | None | None | None | 4179544 | Box Truck | Station Wagon/Sport Utility Vehicle | None | None | None | POINT (988519.261 214979.320) |
| 4 | 07/30/2019 | 10:00 | BROOKLYN | 11223 | 40.600090 | -73.965910 | (40.60009, -73.96591) | AVENUE T | OCEAN PARKWAY | None | ... | None | None | None | 4180660 | Station Wagon/Sport Utility Vehicle | Bike | None | None | None | POINT (993716.669 157907.212) |
5 rows × 30 columns
LATITUDE와 LONGITUDE 열을 사용하여 대화형 지도를 만들어 충돌 데이터를 시각화해보세요.
어떤 유형의 지도가 가장 효과적이라고 생각하시나요?
m_1 = folium.Map(location = [40.7, -74], zoom_start = 11)
HeatMap(data = collisions[['LATITUDE', 'LONGITUDE']], radius = 9).add_to(m_1)
m_1 # embed_map(m_1, 'q_1.html')2) 병원의 서비스 범위를 이해
다음 셀을 실행하여 병원 데이터를 로드해보세요.
hospitals = gpd.read_file('./geospatial-learn-course-data/nyu_2451_34494/nyu_2451_34494/nyu_2451_34494.shp')
hospitals.head()| id | name | address | zip | factype | facname | capacity | capname | bcode | xcoord | ycoord | latitude | longitude | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 317000001H1178 | BRONX-LEBANON HOSPITAL CENTER - CONCOURSE DIVI... | 1650 Grand Concourse | 10457 | 3102 | Hospital | 415 | Beds | 36005 | 1008872.0 | 246596.0 | 40.843490 | -73.911010 | POINT (1008872.000 246596.000) |
| 1 | 317000001H1164 | BRONX-LEBANON HOSPITAL CENTER - FULTON DIVISION | 1276 Fulton Ave | 10456 | 3102 | Hospital | 164 | Beds | 36005 | 1011044.0 | 242204.0 | 40.831429 | -73.903178 | POINT (1011044.000 242204.000) |
| 2 | 317000011H1175 | CALVARY HOSPITAL INC | 1740-70 Eastchester Rd | 10461 | 3102 | Hospital | 225 | Beds | 36005 | 1027505.0 | 248287.0 | 40.848060 | -73.843656 | POINT (1027505.000 248287.000) |
| 3 | 317000002H1165 | JACOBI MEDICAL CENTER | 1400 Pelham Pkwy | 10461 | 3102 | Hospital | 457 | Beds | 36005 | 1027042.0 | 251065.0 | 40.855687 | -73.845311 | POINT (1027042.000 251065.000) |
| 4 | 317000008H1172 | LINCOLN MEDICAL & MENTAL HEALTH CENTER | 234 E 149 St | 10451 | 3102 | Hospital | 362 | Beds | 36005 | 1005154.0 | 236853.0 | 40.816758 | -73.924478 | POINT (1005154.000 236853.000) |
LATITUDE와 LONGITUDE 열을 사용하여 병원 위치를 시각화해보세요.
m_2 = folium.Map(location=[40.7, -74], zoom_start=11)
for idx, row in hospitals.iterrows():
Marker([row['latitude'], row['longitude']], popup = row['name']).add_to(m_2)
m_2 # embed_map(m_2, 'q_2.html')3) 가장 가까운 병원이 10km 이상 떨어진 충돌 발생 시점은 언제였나요?
가장 가까운 병원에서 10km 이상 떨어진 곳에서 발생한 충돌이 있는 collisions의 모든 행을 포함하는 outside_range DataFrame을 생성합니다.
hospitals와 collisions DataFrame 모두 좌표 참조 시스템 (CRS)로 EPSG 2263을 사용하며, EPSG 2263는 미터 단위를 사용합니다.
buffer = gpd.GeoDataFrame(geometry = hospitals['geometry']).buffer(10000)
my_union = buffer.geometry.unary_union
outside_range = collisions.loc[~collisions['geometry'].apply(lambda x : my_union.contains(x))]
outside_range.head()| DATE | TIME | BOROUGH | ZIP CODE | LATITUDE | LONGITUDE | LOCATION | ON STREET | CROSS STRE | OFF STREET | ... | CONTRIBU_2 | CONTRIBU_3 | CONTRIBU_4 | UNIQUE KEY | VEHICLE TY | VEHICLE _1 | VEHICLE _2 | VEHICLE _3 | VEHICLE _4 | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 07/30/2019 | 0:00 | BRONX | 10464 | 40.841100 | -73.784960 | (40.8411, -73.78496) | None | None | 121 PILOT STREET | ... | Unspecified | None | None | 4180045 | Sedan | Station Wagon/Sport Utility Vehicle | Station Wagon/Sport Utility Vehicle | None | None | POINT (1043750.211 245785.815) |
| 1 | 07/30/2019 | 0:10 | QUEENS | 11423 | 40.710827 | -73.770660 | (40.710827, -73.77066) | JAMAICA AVENUE | 188 STREET | None | ... | None | None | None | 4180007 | Sedan | Sedan | None | None | None | POINT (1047831.185 198333.171) |
| 5 | 07/30/2019 | 10:50 | QUEENS | 11423 | 40.721060 | -73.759450 | (40.72106, -73.75945) | FRANCIS LEWIS BOULEVARD | HILLSIDE AVENUE | None | ... | None | None | None | 4179812 | Sedan | Box Truck | None | None | None | POINT (1050928.749 202069.687) |
| 6 | 07/30/2019 | 10:55 | QUEENS | 11434 | 40.676228 | -73.761120 | (40.676228, -73.76112) | CRANDALL AVENUE | CHENEY STREET | None | ... | None | None | None | 4180464 | Station Wagon/Sport Utility Vehicle | Station Wagon/Sport Utility Vehicle | None | None | None | POINT (1050510.380 185734.852) |
| 15 | 07/30/2019 | 13:05 | None | None | 40.588413 | -74.166725 | (40.588413, -74.166725) | None | None | 26 RICHMOND HILL ROAD | ... | None | None | None | 4180091 | Station Wagon/Sport Utility Vehicle | Box Truck | None | None | None | POINT (937943.004 153695.210) |
5 rows × 30 columns
다음 셀은 가장 가까운 병원에서 10km 이상 떨어진 곳에서 발생한 충돌의 비율을 계산합니다.
percentage = round(len(outside_range) / len(collisions) * 100, 2)
print('Percentage of collisions more than 10km away from the closest hospital : {}%'.format(percentage))Percentage of collisions more than 10km away from the closest hospital : 15.12%
4) 추천하기
먼 곳에서 충돌 사고가 발생하면 부상자를 가장 가까운 병원으로 이송하는 것이 더욱 중요해집니다.
이를 염두에 두고, 다음과 같은 추천을 만들기로 결정합니다.
- 충돌 위치(EPSG 2263)를 입력으로 받습니다.
- 가장 가까운 병원을 찾습니다(거리 계산은 EPSG 2263으로 수행).
- 가장 가까운 병원의 이름을 반환합니다.
def best_hospital(collision_location) :
idx_min = hospitals['geometry'].distance(collision_location).idxmin()
my_hospital = hospitals.iloc[idx_min]
name = my_hospital['name']
return name
print(best_hospital(outside_range['geometry'].iloc[0]))CALVARY HOSPITAL INC
5) 가장 수요가 많은 병원은 어디일까요?
outside_range DataFrame의 충돌만 고려할 때, 가장 추천하는 병원은 어디일까요?
정답은 4) 에서 생성한 함수가 반환한 병원 이름과 정확히 일치해야합니다.
highest_demand = outside_range['geometry'].apply(best_hospital).value_counts().idxmax()
highest_demand'JAMAICA HOSPITAL MEDICAL CENTER'
6) 시에서 새로운 병원을 어디에 건설해야 할까요?
다음 셀을 실행하여 가장 가까운 병원에서 10km 이상 떨어진 곳에서 발생한 충돌과 병원의 위치를 시각화해보세요.
m_6 = folium.Map(location = [40.7, -74], zoom_start = 11)
coverage = gpd.GeoDataFrame(geometry = hospitals['geometry']).buffer(10000)
folium.GeoJson(coverage.geometry.to_crs(epsg = 4326)).add_to(m_6)
HeatMap(data = outside_range[['LATITUDE', 'LONGITUDE']], radius = 9).add_to(m_6)
folium.LatLngPopup().add_to(m_6)
m_6 # embed_map(m_6, 'm_6.html')지도의 아무 곳이나 클릭하면 해당 위치가 위도와 경도로 표시된 팝업이 표시됩니다.
뉴욕 시에서 새로운 병원 두 곳의 입지를 결정하는데 도움을 요청하는 연락이 왔습니다. 특히 3) 단계에서 계산된 비율을 10% 미만으로 낮추기 위해 위치를 식별하는데 도움을 요청합니다.
지도를 사용하여(그리고 구역법이나 병원을 짓기 위해 특정 건물을 철거해야 하는지에 대해 걱정하지 않고) 이 목표를 달성하는데 도움이 될 두 곳의 위치를 찾을 수 있나요?
병원 1의 제안된 위도와 경도를 각각 lat_1, lon_1으로 할당하세요. (병원 2도 마찬가지입니다.)
그리고, 다음 셀을 실행하여 새로운 병원의 효과를 확인합니다. 두 개의 새 병원을 통해 백분율이 10% 미만이 되면 정답입니다.
lat_1, lon_1 = 40.6714, -73.8492
lat_2, lon_2 = 40.6702, -73.7612
new_df = pd.DataFrame(
{'Latitude' : [lat_1, lat_2],
'Longitude' : [lon_1, lon_2]})
new_gdf = gpd.GeoDataFrame(new_df, geometry = gpd.points_from_xy(new_df['Longitude'], new_df['Latitude']))
new_gdf.crs = {'init' : 'epsg:4326'}
new_gdf = new_gdf.to_crs(epsg = 2263)
new_coverage = gpd.GeoDataFrame(geometry = new_gdf.geometry).buffer(10000)
new_my_union = new_coverage.geometry.unary_union
new_outside_range = outside_range.loc[~outside_range['geometry'].apply(lambda x : new_my_union.contains(x))]
new_percentage = round(len(new_outside_range) / len(collisions) * 100, 2)
print('(NEW) Percentage of collisions more than 10km away from the closest hospital : {}%'.format(new_percentage))
m = folium.Map(location = [40.7, -74], zoom_start = 11)
folium.GeoJson(coverage.geometry.to_crs(epsg = 4326)).add_to(m)
folium.GeoJson(new_coverage.geometry.to_crs(epsg = 4326)).add_to(m)
for idx, row in new_gdf.iterrows() :
Marker([row['Latitude'], row['Longitude']]).add_to(m)
HeatMap(data = new_outside_range[['LATITUDE', 'LONGITUDE']], radius = 9).add_to(m)
folium.LatLngPopup().add_to(m)
display(m) # embed_map(m, 'q_6.html')(NEW) Percentage of collisions more than 10km away from the closest hospital : 9.12%
축하합니다!
Geospatial Analysis 강좌를 완료하였습니다! 고생하셨습니다!
Have questions or comments? Visit the course discussion forum to chat with other learners.